﻿using System.Text;

namespace DoNet.Token.Common
{
    /// <summary>
    /// 创建一个在本地唯一的短字符串生成对象
    /// </summary>
    public class StringGenerate
    {
        /// <summary>
        /// 可用字符
        /// 根据需求可加入小写abcdefghijklmnopqrstuvwxyz
        /// </summary>
        private static char[] sc = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
        /// <summary>
        /// 起始时间
        /// 起始时间越大，时间戳就越小，字符串才能越短
        /// </summary>
        private static DateTime startTime = new DateTime(1900, 1, 1, 0, 0, 0, 0);
        /// <summary>
        /// 字符串前缀
        /// </summary>
        private static long prve = 0;
        /// <summary>
        /// 位数设置
        /// </summary>
        //private static int len = 8;
        /// <summary>
        /// 锁
        /// </summary>
        private static readonly object _lock = new object();
        
        /// <summary>
        /// 生成一个唯一的短字符串
        /// </summary>
        /// <param name="len"></param>
        /// <returns></returns>
        public string Create(int len = 8)
        {
            lock (_lock)
            {
                //使用时间戳确保不会重复
                TimeSpan ts = DateTime.UtcNow - startTime;
                //毫秒1000*10，每秒自增（0-9999）
                long tempSeconds = Convert.ToInt64(ts.TotalMilliseconds * 10);
                //防重复冗余设置（前缀自增，未超过当前时间戳就用）
                prve = tempSeconds > prve ? tempSeconds : prve++;
                //获取字符串
                return GetShortString(prve, len);
            }
        }

        /// <summary>
        /// 使用进制生成短字符串
        /// </summary>
        /// <param name="num">毫秒自增时间戳</param>
        /// <param name="len">位数设置</param>
        /// <returns></returns>
        private string GetShortString(long num, int len)
        {
            var str = "";
            while (num >= sc.Length)
            {
                //取余赋值
                str = sc[num % sc.Length] + str;
                num = num / sc.Length;
            }
            var ret = sc[num] + str;

            if (ret.Length > len)
            {
                return ret.Substring(0, len);
            }
            else
            {
                StringBuilder sbPre = new StringBuilder();
                for (int x = 0; x < len - ret.Length; x++)
                {
                    Random random = new Random();
                    //随机取字符串数组字符
                    var index = random.Next(0, sc.Length - 1);
                    //累加字符串
                    sbPre.Append(sc[index]);
                }
                //拼接
                return sbPre.ToString() + ret;
            }
        }
    }
}
